using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Globalization;
using Lizk.WebScraper;
using HtmlAgilityPack;

namespace MovieScrapers
{
    public class ImdbScraper : Scraper
    {
        public override ScraperResult GetTitleInfo(string id)
        {
            ScraperResult title = new ScraperResult(id);
            GetTitleInfo(title);
            ScrapeComplete(title);
            return title;
             
        }

        public void GetEpisodes(ScraperResult title)
        {
            WebClient client = new WebClient();
            
            using (StreamReader streamReader = new StreamReader(client.OpenRead("http://www.imdb.com/title/" + title.ID + "/episodes")))
            {
                string line;
                while ((line = streamReader.ReadLine()) != null)
                {
                    if (!line.Contains("<tr><td style=\"padding-top: 5px; padding-bottom: 5px\"><a name="))
                        continue;

                    Episode episode = new Episode();

                    int endindex = 0;
                    string input;
                    if ((input = Scrape(endindex, line, "white-space: nowrap\">", ": <a href=\"/title/", out endindex) ) != null)
                    {
                        episode.Season = Int32.Parse(input.Substring(input.IndexOf(' ') + 1, input.IndexOf(',') - 1 - input.IndexOf(' ')));
                        episode.EpisodeNumber = Int32.Parse(input.Substring(input.LastIndexOf(' ') + 1, input.Length - input.LastIndexOf(' ') - 1));
                        
                        input = Scrape(endindex, line, "/\">", "</a></span>", out endindex);
                        if (input != null)
                        {
                            episode.Title = input;
                        }

                        input = Scrape(endindex, line, "<br><b>", "</b>", out endindex);
                        if (input != null)
                        {
                            try
                            {
                                episode.AirDate = DateTime.Parse(input);
                            }
                            catch
                            {
                                try
                                {
                                    int i = Int32.Parse(input);
                                    episode.AirDate = new DateTime(i, 1, 1);
                                }
                                catch
                                {
                                }
                            }
                        }

                        input = Scrape(endindex, line, "<br>", "<br></td></tr>", out endindex);
                        if (input != null)
                        {
                            episode.Summary = input;
                        }
                        title.Episodes.Add(episode);
                    }
                }
            }
        }
        Regex patternName = new Regex("(?:.*?<a href=\"/name/(.+?)/\">(.+?)</a>(?:.*?\\(([^\\)]+)\\))?.*?)+");
        Regex patternActor = new Regex("(?:.*?<a href=\"/name/(.+?)/\">(.+?)</a></td><td class=\"ddd\"> ... </td><td class=\"char\">(.+?)</td>)+");
        Regex patternGenre = new Regex("(?:.*?<a href=\"/Sections/Genres/(?:.+?)/\">(.+?)</a>)+");
        Regex patternCountry = new Regex("(?:.*?<a href=\"/Sections/Countries/(?:.+?)/\">(.+?)</a>)+");
        Regex patternRating = new Regex("([^/]+)/10");
        Regex patternVotes = new Regex("([^\\s]+) votes");
        Regex patternRuntime = new Regex(@"\s*(\d+)\s*min");

        Regex patternTitle = new Regex("<h1>(.*?) <span>\\(<a href=\"/Sections/Years/(\\d+)\">");
        private void GetTitleInfo(ScraperResult title)
        {
            WebClient client = new WebClient();

            UpdateProgress(new ScraperEventArgs("Connecting to IMDB", ScraperEventArgs.ScaperStatus.Connecting));

            StreamReader streamReader = new StreamReader(client.OpenRead("http://www.imdb.com/title/" + title.ID + "/"));
            FillTitle(title, streamReader.ReadToEnd());


            UpdateProgress(new ScraperEventArgs("Information Scraped", ScraperEventArgs.ScaperStatus.Done));


        }

        private void FillTitle(ScraperResult title, string input)
        {
            using (StringReader streamReader = new StringReader(input))
            {
                HtmlDocument html = new HtmlDocument();
                html.LoadHtml(streamReader.ReadToEnd());
            
                HtmlNodeCollection nc = html.DocumentNode.SelectNodes("//div[@id='tn15title']/h1");
                if(nc != null)
                foreach (HtmlNode node in nc)
                {
                    title.Title = HttpUtility.HtmlDecode(node.FirstChild.InnerText.Trim());
                }
                nc = html.DocumentNode.SelectNodes("//div[@id='tn15title']/h1/span/a");
                int year;
                if (nc != null && nc.Count == 1 && Int32.TryParse(nc[0].InnerText, out year))
                    title.Year = year;

                nc = html.DocumentNode.SelectNodes("//div[@id='tn15rating']/div[@class='general rating']/b");

                if (nc != null && nc.Count == 2)
                {
                    Match m = patternRating.Match(nc[1].InnerText);
                    if (m.Success)
                    {
                        NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
                        title.Rating = float.Parse(m.Groups[1].Value, nfi);
                    }

                }
                nc = html.DocumentNode.SelectNodes("//div[@id='tn15lhs']/div[@class='photo']/a/img");
                if (nc != null)
                {
                    title.ImageUrl = nc[0].Attributes["src"].Value;
                }
                nc = html.DocumentNode.SelectNodes("//div[@class='info'][h5='Director:']/a");
                if (nc != null)
                {
                    foreach (HtmlNode node in nc)
                    {
                        if (node.GetAttributeValue("class", "") != "")
                            continue;
                        Person person = new Person(node.Attributes["href"].Value.Replace("/name/","").Replace("/",""), HttpUtility.HtmlDecode(node.InnerText));
                        person.Job = "Director";
                        title.People.Add(person);
                    }
                }

                nc = html.DocumentNode.SelectNodes("//div[@class='info'][starts-with(h5, 'Writers')]/a");
                if (nc != null)
                {
                    foreach (HtmlNode node in nc)
                    {
                        if (node.GetAttributeValue("class", "") != "")
                            continue;
                        Person person = new Person(node.Attributes["href"].Value.Replace("/name/", "").Replace("/", ""), HttpUtility.HtmlDecode(node.InnerText));
                        person.Job = "Writer";
                        title.People.Add(person);
                    }
                }

                nc = html.DocumentNode.SelectNodes("//div[@class='info'][starts-with(h5, 'Genre:')]/a");
                if (nc != null)
                {
                    foreach (HtmlNode node in nc)
                    {
                        if (node.GetAttributeValue("class", "") != "")
                            continue;
                        title.Genres.Add(HttpUtility.HtmlDecode(node.InnerText));
                    }
                }

                nc = html.DocumentNode.SelectNodes("//div[@class='info'][starts-with(h5, 'Plot Outline:')]");
                if (nc != null)
                {
                    title.Summary = HttpUtility.HtmlDecode(nc[0].ChildNodes[2].InnerText.Trim());
                }

                nc = html.DocumentNode.SelectNodes("//div[@class='info'][starts-with(h5, 'Tagline:')]");
                if (nc != null)
                {
                    title.TagLine = HttpUtility.HtmlDecode(nc[0].ChildNodes[2].InnerText.Trim());
                }


                nc = html.DocumentNode.SelectNodes("//div[@class='info'][starts-with(h5, 'Runtime:')]");
                if (nc != null)
                {
                    Match m = patternRuntime.Match(nc[0].ChildNodes[2].InnerText.Trim());
                    if (m.Success)
                    {
                        title.Runtime = new TimeSpan(0, Int32.Parse(HttpUtility.HtmlDecode(m.Groups[1].Value)), 0);
                    }
                }

                nc = html.DocumentNode.SelectNodes("//div[@id='tn15rating']/div[@class='general rating']/small/a");

                if (nc != null && nc.Count == 1)
                {
                    Match m = patternVotes.Match(nc[0].InnerText);
                    if (m.Success)
                    {
                        NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
                        int votes;
                        if (Int32.TryParse(m.Groups[1].Value, NumberStyles.AllowThousands, nfi, out votes))
                            title.Votes = votes;

                    }

                }

                nc = html.DocumentNode.SelectNodes("//table[@class='cast']/tr/td[@class='nm']/a");

                if (nc != null)
                {
                    foreach (HtmlNode node in nc)
                    {
                        Person person = new Person(node.Attributes["href"].Value.Replace("/name/", "").Replace("/", ""), HttpUtility.HtmlDecode(node.InnerText).Trim());
                        person.Role = HttpUtility.HtmlDecode(node.ParentNode.NextSibling.NextSibling.InnerText);
                        person.Job = "Actor";
                        title.People.Add(person);
                    }

                }


            }

        }

        Regex patternTitleID = new Regex(@"(tt\d+)");
        public override ScraperResult[] Search(string search)
        {
            Regex titleGrabber = new Regex("/title/(tt\\d+)/");///.+?\">(.+?)");//</a>.*?\\((.+?)\\).*?(?:<br>&#160;aka <em>(.+?)</em>.*?)*</td>$");

            Dictionary<string, ScraperResult> titles = new Dictionary<string, ScraperResult>();

            UpdateProgress(new ScraperEventArgs("Connecting to imdb.com", ScraperEventArgs.ScaperStatus.Connecting));
            HttpWebResponse response = Connect(new Uri("http://www.imdb.com/find?s=tt&q=" + HttpUtility.UrlEncode(search)));
            Match m = patternTitleID.Match(response.ResponseUri.ToString());
            if (m.Success)
            {
                UpdateProgress(new ScraperEventArgs("Search completed", ScraperEventArgs.ScaperStatus.Done));
                ScraperResult title = new ScraperResult(m.Groups[1].ToString());
                string text;
                using(StreamReader s = new StreamReader(response.GetResponseStream())) 
                {
                    text = s.ReadToEnd();
                }
                FillTitle(title, text);
                ScrapeComplete(title);
                return new ScraperResult[] { title };

            }
            int[] matchTypes = new int[3];

            using (StreamReader s = new StreamReader(response.GetResponseStream()))
            {
                HtmlDocument html = new HtmlDocument();
                html.LoadHtml(s.ReadToEnd());

                // Get Popular Titles 
                HtmlNodeCollection nc = html.DocumentNode.SelectNodes("//tr/td/a[starts-with(@href, '/title/tt')]");
                foreach (HtmlNode node in nc)
                {
                    if (node.Attributes.Count != 1)
                        continue;

                    string id = node.Attributes["href"].Value.Replace("/title/", "").Replace("/", "");
                    if (!titles.ContainsKey(id))
                    {
                        ScraperResult sr = new ScraperResult(id);
                        sr.Title = HttpUtility.HtmlDecode(node.InnerText + node.NextSibling.InnerText);
                        titles.Add(id, sr);
                    }
                }
            }
                
            UpdateProgress(new ScraperEventArgs("Search completed", ScraperEventArgs.ScaperStatus.Done));

            SearchComplete(titles.Values);
            
            return new List<ScraperResult>(titles.Values).ToArray();
        }
    }
}
